# 日志功能主逻辑

import os
import re
import time
import threading
import getpass,win32api,shutil
import tkinter.messagebox
import public

username = getpass.getuser()
# 创建临时文件夹
make_dir = 'C:\\Users\\' + username + '\\Documents\\DA_Tools\\'
# 创建页面文件，记录文件状态
make_dir_s = make_dir + 'adb_test_temp\\'
# 日志保存路径
android_log_path = 'C:\\Users\\' + username + '\\Desktop\\adb_android_logcat'
# 工具全局通用配置文件
adb_config_path = make_dir_s + 'adb_config.ini'
adb_log_config_text = 'adb_log_state'  # 设置配置的字段
LOGO_path = public.resource_path(os.path.join('icon', 'android.ico'))
# 实时保存设备序列号
devices_log = make_dir_s + 'devices.log'
# 根据日志内容过滤得到的日志文件路径
grep_log_path = android_log_path + '\\grep_log.log'


def kill_logcat(device):
    """强制结束logcat服务"""
    logcat_process = public.execute_cmd('adb -s ' + device + ' shell ps -A | findstr logcat')
    print(logcat_process)
    logcat_process_finally = [i for i in logcat_process.split(' ') if i != ''][1]
    public.execute_cmd('adb -s ' + device + ' shell kill ' + logcat_process_finally)


class Context:
    """构建中间变量"""


def main_log_run(device):
    """logcat服务启动中"""
    def logcat_service():
        public.adb_config_ini(adb_log_config_text,'logcat')
        if not os.path.exists(android_log_path):
            os.makedirs(android_log_path)
        now = time.localtime()
        now_time = time.strftime("%Y-%m-%d_%H%M%S", now)
        logcat_file = android_log_path + '\\logcat-' + now_time
        setattr(Context,"logcat_file",logcat_file)
        os.makedirs(logcat_file)
        log_file_num = 1  # 默认文件名序号为 1
        setattr(Context, "log_file_num", log_file_num)
        setattr(Context, "clear_log_flag", False)  # 默认设置False
        while True:
            try:
                getattr(Context,"log_str").set('正在记录logcat_' + str(log_file_num))
            except Exception:
                pass
            clear_log_flag = getattr(Context,"clear_log_flag")
            if not clear_log_flag:
                public.execute_cmd('adb -s ' + device + ' logcat -v time > ' + logcat_file + '\\logcat_' + str(log_file_num) + '.log')
                file_size_flag = getattr(Context,"out_of_file_size")
                if file_size_flag:  # 只有单文件日志大小达到要求才能加1，其他设备连接不稳定等情况一律覆盖当前日志文件
                    log_file_num += 1
            adb_log_config_read = open(adb_config_path,'r').read()
            adb_log_re = ''.join(re.findall(adb_log_config_text + '=(.*?)\n', adb_log_config_read,re.S))
            # print('匹配获取的字段',adb_log_re)
            if adb_log_re.strip() == 'closed':
                print('logcat服务已停止！')
                break

    def logcat_control():
        time.sleep(2)
        setattr(Context, "out_of_file_size", False)
        while True:
            logcat_files = getattr(Context,"logcat_file") + '\\logcat_' + str(getattr(Context,"log_file_num")) + '.log'
            log_size = os.stat(logcat_files).st_size
            if log_size > 20971520:
                kill_logcat(device)
                setattr(Context, "out_of_file_size", True)
                time.sleep(2)
                setattr(Context, "out_of_file_size", False)
            adb_log_config_read = open(adb_config_path, 'r').read()
            adb_log_re = ''.join(re.findall(adb_log_config_text + '=(.*?)\n', adb_log_config_read, re.S))
            if adb_log_re.strip() == 'closed':
                print('logcat控制已停止！')
                break
            time.sleep(3)

    logcat_service = threading.Thread(target=logcat_service)
    logcat_service.setDaemon(True)
    logcat_service.start()

    logcat_control = threading.Thread(target=logcat_control)
    logcat_control.setDaemon(True)
    logcat_control.start()


def update_log_state(device_type_str,log_label,log_opened_label,log_stop_button,device,adb_test_close,adb_test_close_disable):
    """点击更新log label状态"""
    setattr(Context, "adb_test_close", adb_test_close)
    setattr(Context, "adb_test_close_disable", adb_test_close_disable)
    adb_test_close_disable.bind('<Button-1>',lambda x:tkinter.messagebox.showinfo('禁止退出','您正在使用“日志记录”功能，暂时无法点击退出ADB测试工具哦！'))
    adb_test_close.place_forget()
    adb_test_close_disable.place(x=400, y=370)
    device_state = public.device_connect()
    if not device_state:
        tkinter.messagebox.showinfo('启动失败', '没有连接任何设备，无法正常使用该功能')
        adb_test_close_disable.place_forget()
        adb_test_close.place(x=400, y=370)
        adb_test_close_disable.unbind('<Button-1>')
    else:
        if device_type_str.strip() == 'Android（安卓）':
            setattr(Context, "log_label", log_label)
            setattr(Context,"log_stop_button",log_stop_button)
            setattr(Context,"log_opened_label",log_opened_label)
            log_label.place_forget()
            log_opened_label.place(x=435, y=425)
            log_stop_button.place(x=550,y=415)
            # 进入Log操作详情页面
            log = AndroidLog()
            log_opened_label.bind('<Button-1>',lambda x:log.log_form())
            setattr(Context,"log_opened_label",log_opened_label)
            # 启动logcat
            main_log_run(device)
        else:
            tkinter.messagebox.showinfo('启动失败','当前日志功能暂支持安卓设备！')
            adb_test_close_disable.place_forget()
            adb_test_close.place(x=400, y=370)
            adb_test_close_disable.unbind('<Button-1>')


def stop_log(device,log_stop_button,log_opened_label,log_label):
    def t_stop_log():
        """停止记录日志"""
        # 修改配置为closed
        log_stop_button.place_forget()
        log_opened_label.place_forget()
        log_label.place(x=450, y=425)
        public.adb_config_ini(adb_log_config_text,'closed')
        try:
            kill_logcat(device)
        except Exception:
            print('设备已断开！无需进行中断logcat操作！')
        print('日志记录已停止！')
        if getattr(Context,"log_root").winfo_exists() == 0:
            getattr(Context,"adb_test_close_disable").place_forget()
            getattr(Context,"adb_test_close").place(x=400, y=370)
            getattr(Context,"adb_test_close_disable").unbind('<Button-1>')

    t_stop_log = threading.Thread(target=t_stop_log)
    t_stop_log.setDaemon(True)
    t_stop_log.start()


class AndroidLog(object):
    def log_form(self):
        self.log_root = tkinter.Toplevel()
        self.log_root.title('Android 日志详情操作')
        w = 310
        h = 300
        self.log_root.geometry('%dx%d' % (w, h))
        self.log_root.iconbitmap(LOGO_path)
        self.log_root.resizable(0, 0)

        setattr(Context,"log_root",self.log_root)
        getattr(Context,"log_opened_label").unbind('<Button-1>')
        self.main_form()
        self.log_root.protocol('WM_DELETE_WINDOW', self.close_handle)

    def close_handle(self):
        getattr(Context, "log_opened_label").bind('<Button-1>',lambda x:self.log_form())
        self.log_root.destroy()
        adb_log_config_read = open(adb_config_path, 'r').read()
        adb_log_re = ''.join(re.findall(adb_log_config_text + '=(.*?)\n', adb_log_config_read, re.S))
        if adb_log_re.strip() == 'closed':
            getattr(Context, "adb_test_close_disable").place_forget()
            getattr(Context, "adb_test_close").place(x=400, y=370)
            getattr(Context, "adb_test_close_disable").unbind('<Button-1>')

    def main_form(self):
        # 状态栏
        self.log_str = tkinter.StringVar()
        setattr(Context,"log_str",self.log_str)
        self.log_label = tkinter.Label(self.log_root, textvariable=self.log_str, bg='black', fg='#FFFFFF',
                                           width=35, height=2)
        self.log_label.place(x=35, y=10)
        self.log_str.set('正在记录logcat_' + str(getattr(Context,"log_file_num")))

        # 清空日志缓存信息
        self.clear_log_button = tkinter.Button(self.log_root, text='清空日志缓存信息', width=30)
        self.clear_log_button.bind('<Button-1>', lambda x: self.clear_log())
        self.clear_log_button_disable = tkinter.Button(self.log_root, text='正在清空中...', width=30)
        self.clear_log_button_disable.config(state='disable')
        self.clear_log_button.place(x=50, y=60)

        # 打开Android日志文件夹
        self.open_syslog_button = tkinter.Button(self.log_root, text='打开Android日志文件夹', width=30)
        self.open_syslog_button.bind('<Button-1>', lambda x: self.open_log())
        self.open_syslog_button_disable = tkinter.Button(self.log_root, text='正在打开...', width=30)
        self.open_syslog_button_disable.config(state='disable')
        self.open_syslog_button.place(x=50, y=95)

        # 过滤日志输入框
        self.log_grep_entry = tkinter.Entry(self.log_root,width=30)
        self.log_grep_entry.place(x=50,y=130)

        # 过滤日志并保存
        self.log_grep_button = tkinter.Button(self.log_root, text='过滤并保存', width=15)
        self.log_grep_button.bind('<Button-1>', lambda x: self.grep_log())
        self.log_grep_button_disable = tkinter.Button(self.log_root, text='正在过滤...', width=15)
        self.log_grep_button_disable.config(state='disable')
        self.log_grep_button.place(x=50, y=165)

        # 打开过滤日志文本
        self.open_log_grep_button = tkinter.Button(self.log_root, text='打开过滤日志文本', width=15)
        self.open_log_grep_button.bind('<Button-1>', lambda x: self.open_log_grep())
        self.open_log_grep_button_disable = tkinter.Button(self.log_root, text='正在打开...', width=15)
        self.open_log_grep_button_disable.config(state='disable')
        self.open_log_grep_button.place(x=170, y=165)

        # 重置Android日志文件夹
        self.del_syslog_button = tkinter.Button(self.log_root, text='重置Android日志文件夹', width=30)
        self.del_syslog_button.bind('<Button-1>', lambda x: self.del_log_grep())
        self.del_syslog_button_disable = tkinter.Button(self.log_root, text='正在重置...', width=30)
        self.del_syslog_button_disable.config(state='disable')
        self.del_syslog_button.place(x=50, y=200)

        # 退出日志记录并关闭
        self.exit_syslog_button = tkinter.Button(self.log_root, text='退出日志记录并关闭', width=30)
        self.exit_syslog_button.bind('<Button-1>', lambda x: self.exit_log())
        self.exit_syslog_button_disable = tkinter.Button(self.log_root, text='正在退出...', width=30)
        self.exit_syslog_button_disable.config(state='disable')
        self.exit_syslog_button.place(x=50, y=235)

    def clear_log(self):
        def t_clear_log():
            self.clear_log_button.place_forget()
            self.clear_log_button_disable.place(x=50, y=60)
            devices_state = public.device_connect()
            device = open(devices_log,'r').read()
            content = """
            日志记录规则：
            1.当安卓系统从启动到关闭的这段时间日志一直记录在logcat中
            2.如果清理日志缓存后，之前的日志记录将会清掉，将会从最新的时间开始记录日志
            警告：如之前日志包含重要信息，如崩溃、anr等日志，建议勿使用此功能
            是否要清理日志缓存？
            """
            if tkinter.messagebox.askyesno("温馨提示",content):
                if not devices_state:
                    self.log_str.set('检测到没有连接到设备\n请连接设备后再使用本功能')
                else:
                    device_type = public.device_type_android(device)
                    if device_type.strip() == 'Android':
                        print('正在清理缓存并终止logcat记录...')
                        setattr(Context, "clear_log_flag", True)
                        try:
                            kill_logcat(device)
                            public.execute_cmd('adb -s ' + device + ' logcat -c')
                            print('清理缓存已完成！')
                            setattr(Context, "clear_log_flag", False)
                            tkinter.messagebox.showinfo('清理成功', '清理日志缓存信息已完成！')
                        except IndexError:
                            self.log_str.set('日志记录功能已关闭！\n使用该功能请把日志记录功能打开再使用！')
                    else:
                        self.log_str.set('非Android设备无法使用\n请使用Android设备进行清理缓存')

            self.clear_log_button_disable.place_forget()
            self.clear_log_button.place(x=50, y=60)

        t_clear_log = threading.Thread(target=t_clear_log)
        t_clear_log.setDaemon(True)
        t_clear_log.start()

    def open_log(self):
        def t_open_log():
            self.open_log_grep_button.place_forget()
            self.open_log_grep_button_disable.place(x=170, y=165)
            if not os.path.exists(android_log_path):
                os.makedirs(android_log_path)
            win32api.ShellExecute(0, 'open', android_log_path, '', '', 1)
            self.open_log_grep_button_disable.place_forget()
            self.open_log_grep_button.place(x=170, y=165)

        t_open_log = threading.Thread(target=t_open_log)
        t_open_log.setDaemon(True)
        t_open_log.start()

    def grep_log(self):
        def t_grep_log():
            self.log_grep_button.place_forget()
            self.log_grep_button_disable.place(x=50, y=165)
            devices_state = public.device_connect()
            device = open(devices_log, 'r').read()
            if not devices_state:
                self.log_str.set('检测到没有连接到设备\n请连接设备后再使用本功能')
            else:
                device_type = public.device_type_android(device)
                if device_type.strip() == 'Android':
                    adb_log_config_read = open(adb_config_path, 'r').read()
                    adb_log_re = ''.join(re.findall(adb_log_config_text + '=(.*?)\n', adb_log_config_read, re.S))
                    if adb_log_re.strip() == 'closed':
                        self.log_str.set('日志记录功能已关闭！\n请重新开启日志记录功能再使用！')
                    else:
                        grep_content = self.log_grep_entry.get().strip()
                        if grep_content == '':
                            self.log_str.set('没有输入任何内容\n无法使用该功能！')
                        else:
                            public.linux_sn_cmd('adb -s ' + device + ' logcat -d | findstr ' + grep_content + ' > ' + grep_log_path)  # adb logcat -d | findstr da
                            self.log_str.set('过滤日志已完成并保存！\n正在记录logcat_' + str(getattr(Context, "log_file_num")))
            self.log_grep_button_disable.place_forget()
            self.log_grep_button.place(x=50, y=165)

        t_grep_log = threading.Thread(target=t_grep_log)
        t_grep_log.setDaemon(True)
        t_grep_log.start()

    def open_log_grep(self):
        def t_open_log_grep():
            self.open_log_grep_button.place_forget()
            self.open_log_grep_button_disable.place(x=170, y=165)
            if not os.path.exists(grep_log_path):
                tkinter.messagebox.showinfo("打开异常","你没有进行过滤日志操作，暂时无法打开！")
            else:
                 win32api.ShellExecute(0, 'open', grep_log_path, '', '', 1)
            self.open_log_grep_button_disable.place_forget()
            self.open_log_grep_button.place(x=170, y=165)

        t_open_log_grep = threading.Thread(target=t_open_log_grep)
        t_open_log_grep.setDaemon(True)
        t_open_log_grep.start()

    def del_log_grep(self):
        def t_del_log_grep():
            self.del_syslog_button.place_forget()
            self.del_syslog_button_disable.place(x=50, y=200)
            content = """
            确定是否要重置 Android日志文件夹？
            温馨提示：将会删除所有保存的日志信息，如有重要日志先备份再执行！
            """
            if tkinter.messagebox.askyesno("温馨提示", content):
                device = open(devices_log, 'r').read()
                public.adb_config_ini(adb_log_config_text, 'closed')  # 结束logcat
                adb_log_config_read = open(adb_config_path, 'r').read()
                adb_log_re = ''.join(re.findall(adb_log_config_text + '=(.*?)\n', adb_log_config_read, re.S))
                try:
                    kill_logcat(device)  # 结束logcat服务
                    time.sleep(5)  # 确保服务停止
                except IndexError:
                    pass
                try:
                    shutil.rmtree(android_log_path)  # 删除Android日志文件夹
                    if adb_log_re.strip() == 'logcat':
                        main_log_run(device)  # 重新启动logcat
                    tkinter.messagebox.showinfo("重置成功", "重置Android日志文件夹成功！")
                except PermissionError:
                    main_log_run(device)  # 重新启动logcat
                    tkinter.messagebox.showinfo("重置失败", "当前Android日志文件夹被占用，无法重置成功！\n请确保所有日志文件关闭后再重新重置！")
                except FileNotFoundError:
                    self.log_str.set('Android日志文件夹已清理\n无需重置！')

            self.del_syslog_button_disable.place_forget()
            self.del_syslog_button.place(x=50, y=200)

        t_del_log_grep = threading.Thread(target=t_del_log_grep)
        t_del_log_grep.setDaemon(True)
        t_del_log_grep.start()

    def exit_log(self):
        def t_exit_log_grep():
            self.exit_syslog_button.place_forget()
            self.exit_syslog_button_disable.place(x=50, y=235)
            if tkinter.messagebox.askyesno("退出确认","确定要退出日志记录并关闭？"):
                device = open(devices_log, 'r').read()
                stop_log(device,getattr(Context, "log_stop_button"),getattr(Context, "log_opened_label"),getattr(Context, "log_label"))
                self.close_handle()
            try:
                self.exit_syslog_button_disable.place_forget()
                self.exit_syslog_button.place(x=50, y=235)
            except Exception:
                pass

        t_exit_log_grep = threading.Thread(target=t_exit_log_grep)
        t_exit_log_grep.setDaemon(True)
        t_exit_log_grep.start()